package com.dyh.quickdemozwei.controller.http;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;

/**
 * Description: Http调用
 * Date: 2020/7/7 1:48 下午
 * Author: yzf
 * Version: 1.0
 */
public class HttpSdkClient {
    private static Logger logger = LogManager.getLogger(HttpSdkClient.class);
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private static SSLSocketFactory SSL_SOCKET_FACTORY = null;
    private static HostnameVerifier HOSTNAME_VERIFIER;

    private int readTimeout = 30000;
    private int connectTimeout = 30000;
    private String appUrl;


    private static final TrustManager[] TRUST_MANAGERS = new TrustManager[]{new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }};

    static {
        try {
            SSLContext SSL_CONTEXT = SSLContext.getInstance("SSL");
            SSL_CONTEXT.init((KeyManager[]) null, TRUST_MANAGERS, new SecureRandom());
            SSL_SOCKET_FACTORY = SSL_CONTEXT.getSocketFactory();
        } catch (Exception var1) {
            throw new RuntimeException(var1);
        }

        HOSTNAME_VERIFIER = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
    }

    public HttpSdkClient(String appUrl) {
        this.appUrl = appUrl;
    }

    public String execute(String param, String interFaceUri) throws HttpSdkClientException, ProtocolException {
        return this.execute(param, interFaceUri, this.readTimeout);
    }

    public String execute(String param, String interFaceUri, int timeOut) throws HttpSdkClientException, ProtocolException {
        HttpURLConnection conn = null;
        if (timeOut < 0) {
            timeOut = readTimeout;
        }
        try {
            if(StringUtils.isNotBlank(interFaceUri)) {
                conn = this.getConnection(appUrl + interFaceUri);
            }else {
                conn = this.getConnection(appUrl);
            }
            conn.setConnectTimeout(connectTimeout);
            conn.setReadTimeout(timeOut);
        } catch (IOException e) {
            logger.error("Http请求获取连接异常", e);
            throw new HttpSdkClientException(e);
        }

        conn.setRequestProperty("Content-Type", "application/octet-stream");
        String ctype = "application/json;charset=UTF-8";//发送数据类型，需要指定为json类型
        String method = "POST";     //指定发送的方法
        conn.setRequestProperty("Content-Type", ctype);
        conn.setRequestMethod(method);
        conn.setDoInput(true);
        if (StringUtils.isNotBlank(param)) {
            conn.setDoOutput(true);
            OutputStream out = null;
            try {
                out = conn.getOutputStream();
                out.write(param.getBytes(DEFAULT_CHARSET));
                out.flush();
            } catch (IOException e) {
                logger.error("Http请求异常", e);
                throw new HttpSdkClientException(e);
            } finally {
                IOUtils.closeQuietly(out);
            }
        }
        InputStream in = null;
        String returnJsonString = null;
        try {
            in = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));
            returnJsonString = IOUtils.toString(reader);
        } catch (IOException e) {
            logger.error("Http请求获取结果异常", e);
            throw new HttpSdkClientException(e);
        } finally {
            IOUtils.closeQuietly(in);
        }
        return returnJsonString;
    }

    private HttpURLConnection getConnection(String url) throws IOException {
        HttpURLConnection connection = (HttpURLConnection)(new URL(url)).openConnection();
        if (connection instanceof HttpsURLConnection) {
            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
            httpsConnection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
            httpsConnection.setHostnameVerifier(HOSTNAME_VERIFIER);
        }
        return connection;
    }

    /**
     * Form表单请求，可以文件+参数（POST）
     */
    public String uploadFile(String url, String fileName, InputStream is, Map<String, String> params) throws HttpSdkClientException {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        setRequestConfig(httpPost);
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
            builder.addBinaryBody("file", is, ContentType.MULTIPART_FORM_DATA, fileName);
            //FileBody bin = new FileBody(file);
            //builder.addPart("file", bin);
            if (params != null) {
                for (String key : params.keySet()) {
                    builder.addPart(key,
                            new StringBody(params.get(key), ContentType.create("text/plain", DEFAULT_CHARSET)));
                }
            }

            HttpEntity reqEntity = builder.build();
            httpPost.setEntity(reqEntity);

            // 发起请求 并返回请求的响应
            response = httpclient.execute(httpPost, HttpClientContext.create());
            resultString = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);

        } catch (IOException e) {
            logger.error("Http请求IO异常", e);
            throw new HttpSdkClientException(e);
        } catch (Exception e) {
            logger.error("Http请求系统异常", e);
            throw new HttpSdkClientException(e);
        } finally {
            try {
                if (response != null)
                    response.close();
                is.close();
            } catch (IOException e) {
                logger.error("Http请求异常", e);
                throw new HttpSdkClientException(e);
            }
        }
        return resultString;
    }

    /**
     * 对http请求进行基本设置
     *
     * @param httpRequestBase http请求
     */
    private void setRequestConfig(HttpRequestBase httpRequestBase) {
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectTimeout)
                .setConnectTimeout(connectTimeout).setSocketTimeout(readTimeout).build();
        httpRequestBase.setConfig(requestConfig);
    }

    public String getAppUrl() {
        return appUrl;
    }

    public void setAppUrl(String appUrl) {
        this.appUrl = appUrl;
    }
}
